package cn.redragon.soa.config.redis;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;

/**
 * @Author: Steven HUANG
 * @Date: 2021/2/1
 */
@Data
@Component
public class RedisGenericCacheProcessor implements BeanPostProcessor {

    private Map<String, Type> genericCacheMap = new HashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, final String beanName) {
        Class<?> targetClass = AopUtils.getTargetClass(bean);
        Map<Method, Cacheable> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
                                                                                   (MethodIntrospector.MetadataLookup<Cacheable>) method -> AnnotatedElementUtils
                                                                                       .findMergedAnnotation(method, Cacheable.class));
        annotatedMethods.forEach((method, v) -> {
            if (ArrayUtils.isEmpty(v.cacheNames())) {
                throw new RuntimeException("CacheNames must not be null");
            }
            for (String cacheName : v.cacheNames()) {
                genericCacheMap.put(cacheName, method.getGenericReturnType());
            }
        });
        return bean;
    }

}
